
#include "graphics/font.h"

namespace dw
{
	namespace graphics
	{
		inline int next_p2(int a)
		{
			int rval = 1;

			while(rval < a) rval <<= 1;
			return rval;
		}

		Font::Font(const std::string& filename, const unsigned size) :
			_size(size)
		{
			FT_Init_FreeType(&_ftLibrary);
			FT_New_Face(_ftLibrary, filename.c_str(), 0, &_ftFace);
			FT_Set_Pixel_Sizes(_ftFace, 0, _size);
			
			//ftFace->style_flags |= FT_STYLE_FLAG_BOLD;
			//ftFace->style_flags |= FT_STYLE_FLAG_ITALIC;
		}

		Font::~Font()
		{
			FT_Done_Face(_ftFace);
			FT_Done_FreeType(_ftLibrary);
		}

		Font::Glyph Font::getGlyph(const char c)
		{
			GlyphMap::iterator glyphIter = _glyphMap.find(c);

			if (glyphIter != _glyphMap.end())
				return glyphIter->second;

			Glyph glyph;

			FT_Load_Char(_ftFace, c, FT_LOAD_RENDER);
			
			FT_GlyphSlot ftGlyph		= _ftFace->glyph;
			FT_Bitmap& ftBitmap	= ftGlyph->bitmap;

			glyph.width		= ftBitmap.width;
			glyph.height	= ftBitmap.rows;
			glyph.xoffset = ftGlyph->bitmap_left;
			glyph.yoffset = ftGlyph->bitmap_top;
			glyph.xadvance = ftGlyph->advance.x;
			glyph.yadvance = ftGlyph->advance.y;

			//_width	= next_p2(ftBitmap.width);
			//_height	= next_p2(ftBitmap.rows);

			_width	= next_p2(_size);
			_height	= next_p2(_size);


			GLubyte* data = new GLubyte[2 * _width * _height];

			for(int j = 0; j < _height; ++j) 
				for(int i = 0; i < _width; ++i)
					data[2 * (i + j * _width)] = data[2 * (i + j * _width) + 1] =  ( i >= ftBitmap.width || j >= ftBitmap.rows) ? 0 : ftBitmap.buffer[i + ftBitmap.width * j];


			glGenTextures(1, &(glyph.texID));
			glBindTexture(GL_TEXTURE_2D, glyph.texID);
			glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _width, _height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, data);

			_glyphMap.insert(std::make_pair(c, glyph));

			 delete[] data;

			return glyph;
		}
	}
}